#include "safety_app.h"
#include "safety_board.h"

#if _SAFETY_VERIFYFUNCTION_ENABLE_
/**
 * @brief 删除用户后的操作
 *
 */
static void SafetyOperationAfterDeleteSpecificUserManual(void);

/**
 * @brief 构建与命令相对应的报文
 *
 * @param Command          - 命令
 * @param pDataOut         - 构建后的数据流
 * @param pSizeOut         - 数据流长度
 * @param pResponseTimeOut - 命令响应时间
 * @return bool            - （true：成功 false：失败）
 */
static bool SafetyMessageCorrespondingCommand(SafetyCommandTable_t Command, uint8_t *pDataOut, uint16_t *pSizeOut, uint32_t *pResponseTimeOut);

/**
 * @brief 根据命令解析报文
 *
 * @param Command                - 命令
 * @param pDataIn                - 附带数据流
 * @param DataSize               - 数据长度
 * @param ResponseResult         - 响应结果
 * @return SafetyMessageExecuteResult_t - 解析结果
 */
static SafetyMessageExecuteResult_t SafetyParsingMessagesBasedOnCommands(SafetyCommandTable_t Command, const void *pDataIn, uint16_t DataSize, uint8_t ResponseResult);

/**
 * @brief 响应报文解析结果
 *
 * @param Result - 响应结果
 */
static void SafetyResponseMessageParsingResult(SafetyMessageExecuteResult_t Result);

/**
 * @brief 上报命令执行结果
 *
 * @param Command - 命令
 * @param Result  - 结果
 */
static void SafetyReportingCommandExecutionResults(SafetyCommandTable_t Command, SafetyCommandExecuteResult_t Result);

/**
 * @brief 接收数据完成回调
 *
 */
static void SafetyDataReceivedCallback(void);

/**
 * @brief 唤醒回调
 *
 */
static void SafetyEventWakeupIrqCallback(void);

/**
 * @brief 命令操作回调
 *
 */
static void SafetyCommandOperationCallback(void);

static SafetyTaskApi_t SafetyTaskApi = {0};
static SafetyBitStatus_t SafetyBitStatus = {0};
static SafetyDataPacket_t SafetyDataPacket = {0};

static void SafetyOperationAfterDeleteSpecificUserManual(void)
{
  SafetyBitStatus.DeleteIdent = false;
}

static bool SafetyMessageCorrespondingCommand(SafetyCommandTable_t Command, uint8_t *pDataOut, uint16_t *pSizeOut, uint32_t *pResponseTimeOut)
{
  bool BuildResult = false;

  if ((pDataOut != NULL) && (pSizeOut != NULL))
  {
    switch (Command)
    {
    case SAFETY_SELF_TEST:
    {
      if (SafetyTaskApi.SelfTestCallback.Build != NULL)
      {
        BuildResult = SafetyTaskApi.SelfTestCallback.Build(pDataOut, pSizeOut, pResponseTimeOut);
      }
    }
    break;

    case SAFETY_FACTORY_SETTING:
    {
      if (SafetyTaskApi.FactorySettingCallback.Build != NULL)
      {
        BuildResult = SafetyTaskApi.FactorySettingCallback.Build(pDataOut, pSizeOut, pResponseTimeOut);
      }
    }
    break;

    case SAFETY_GET_EIGENVALUE_FILE:
    {
      if (SafetyTaskApi.GetEigenvalueFileCallback.Build != NULL)
      {
        BuildResult = SafetyTaskApi.GetEigenvalueFileCallback.Build(pDataOut, pSizeOut, pResponseTimeOut);
      }
    }
    break;

    case SAFETY_FORCED_TO_GOTO_SLEEP:
    {
      if (SafetyTaskApi.ForcedToGotoSleepCallback.Build != NULL)
      {
        BuildResult = SafetyTaskApi.ForcedToGotoSleepCallback.Build(pDataOut, pSizeOut, pResponseTimeOut);
      }
    }
    break;

    case SAFETY_LOCAL_REGISTER_USER:
    {
      if (SafetyTaskApi.LocalRegisterUserCallback.Build != NULL)
      {
        BuildResult = SafetyTaskApi.LocalRegisterUserCallback.Build(pDataOut, pSizeOut, pResponseTimeOut);
      }
    }
    break;

    case SAFETY_IDENTIFY_USER_RIGHTS:
    {
      if (SafetyTaskApi.IdentifyUserRightsCallback.Build != NULL)
      {
        BuildResult = SafetyTaskApi.IdentifyUserRightsCallback.Build(pDataOut, pSizeOut, pResponseTimeOut);
      }
    }
    break;

    case SAFETY_DELETE_SPECIFIC_USER:
    {
      if (SafetyTaskApi.DeletingSpecificUsersCallback.Build != NULL)
      {
        BuildResult = SafetyTaskApi.DeletingSpecificUsersCallback.Build(pDataOut, pSizeOut, pResponseTimeOut);
      }
    }
    break;

    case SAFETY_REGISTER_BY_EIGENVALUE:
    {
      if (SafetyTaskApi.RegistrationByEigenvalueCallback.Build != NULL)
      {
        BuildResult = SafetyTaskApi.RegistrationByEigenvalueCallback.Build(pDataOut, pSizeOut, pResponseTimeOut);
      }
    }
    break;

    default:
      break;
    }
  }

  return BuildResult;
}

static SafetyMessageExecuteResult_t SafetyParsingMessagesBasedOnCommands(SafetyCommandTable_t Command, const void *pDataIn, uint16_t DataSize, uint8_t ResponseResult)
{
  SafetyMessageExecuteResult_t ParsingResult = SAFETY_MESSAGE_EXECUTE_ERROR;

  if (pDataIn != NULL)
  {
    switch (Command)
    {
    case SAFETY_SELF_TEST:
    {
      if (SafetyTaskApi.SelfTestCallback.Build != NULL)
      {
        ParsingResult = SafetyTaskApi.SelfTestCallback.Parsing(pDataIn, DataSize, ResponseResult);
      }
    }
    break;

    case SAFETY_FACTORY_SETTING:
    {
      if (SafetyTaskApi.FactorySettingCallback.Build != NULL)
      {
        ParsingResult = SafetyTaskApi.FactorySettingCallback.Parsing(pDataIn, DataSize, ResponseResult);
      }
    }
    break;

    case SAFETY_GET_EIGENVALUE_FILE:
    {
      if (SafetyTaskApi.GetEigenvalueFileCallback.Build != NULL)
      {
        ParsingResult = SafetyTaskApi.GetEigenvalueFileCallback.Parsing(pDataIn, DataSize, ResponseResult);
      }
    }
    break;

    case SAFETY_FORCED_TO_GOTO_SLEEP:
    {
      if (SafetyTaskApi.ForcedToGotoSleepCallback.Build != NULL)
      {
        ParsingResult = SafetyTaskApi.ForcedToGotoSleepCallback.Parsing(pDataIn, DataSize, ResponseResult);
      }
    }
    break;

    case SAFETY_LOCAL_REGISTER_USER:
    {
      if (SafetyTaskApi.LocalRegisterUserCallback.Build != NULL)
      {
        ParsingResult = SafetyTaskApi.LocalRegisterUserCallback.Parsing(pDataIn, DataSize, ResponseResult);
      }
    }
    break;

    case SAFETY_IDENTIFY_USER_RIGHTS:
    {
      if (SafetyTaskApi.IdentifyUserRightsCallback.Build != NULL)
      {
        ParsingResult = SafetyTaskApi.IdentifyUserRightsCallback.Parsing(pDataIn, DataSize, ResponseResult);
      }
    }
    break;

    case SAFETY_DELETE_SPECIFIC_USER:
    {
      if (SafetyTaskApi.DeletingSpecificUsersCallback.Build != NULL)
      {
        ParsingResult = SafetyTaskApi.DeletingSpecificUsersCallback.Parsing(pDataIn, DataSize, ResponseResult);
      }
    }
    break;

    case SAFETY_REGISTER_BY_EIGENVALUE:
    {
      if (SafetyTaskApi.RegistrationByEigenvalueCallback.Build != NULL)
      {
        ParsingResult = SafetyTaskApi.RegistrationByEigenvalueCallback.Parsing(pDataIn, DataSize, ResponseResult);
      }
    }
    break;

    default:
      break;
    }
  }

  return ParsingResult;
}

static void SafetyResponseMessageParsingResult(SafetyMessageExecuteResult_t Result)
{
  switch (Result)
  {
  case SAFETY_MESSAGE_EXECUTE_WAIT:
  {
    PRINT("[safety]: message parsing is in progress.\r\n");

    SafetyBitStatus.MessageExecuteStep = SAFETY_USER_ACTION_TIMEOUT;
    SafetyDelayedStartCommandOperationTask(SafetyBitStatus.CommandTimeout);
  }
  break;

  case SAFETY_MESSAGE_EXECUTE_SUCCESS:
  {
    PRINT("[safety]: message parsed successfully.\r\n");

    SafetyBitStatus.NumberOfRetries = 0;
    SafetyBitStatus.NumberOfTimesSent = 0;
    SafetyBitStatus.MessageExecuteStep = SAFETY_USER_ACTION_RESPONSE;

    SafetyStartCommandOperationTaskNoWait();
  }
  break;

  case SAFETY_MESSAGE_EXECUTE_RETRY:
  {
    if (SafetyBitStatus.NumberOfRetries < SAFETY_MAX_NUMBER_OF_QUERY)
    {
      PRINT("[safety]: re-request device status.\r\n");

      SafetyBitStatus.NumberOfRetries++;
      SafetyBitStatus.NumberOfTimesSent = 0;
      SafetyBitStatus.MessageExecuteStep = SAFETY_USER_ACTION_RESPONSE;

      SafetyDelayedStartCommandOperationTask(SafetyBitStatus.CommandTimeout);
    }
    else
    {
      PRINT("[safety]: failed to get status.\r\n");

      SafetyBitStatus.MessageExecuteStep = SAFETY_COMMAND_EXECUTE_FAILURE;
      SafetyStartCommandOperationTaskNoWait();
    }
  }
  break;

  case SAFETY_MESSAGE_EXECUTE_OVER:
  {
    PRINT("[safety]: command is executed.\r\n");

    SafetyBitStatus.CommandExecuteResult = SAFETY_COMMAND_SUCCESS;
    SafetyBitStatus.MessageExecuteStep = SAFETY_MESSAGE_RESPONSE_COMPLETE;
    SafetyStartCommandOperationTaskNoWait();
  }
  break;

  case SAFETY_MESSAGE_EXECUTE_USER_IS_FULL:
  {
    PRINT("[safety]: user is full.\r\n");

    SafetyBitStatus.CommandExecuteResult = SAFETY_COMMAND_USER_IS_FULL;
    SafetyBitStatus.MessageExecuteStep = SAFETY_MESSAGE_RESPONSE_EXCEPTION;
    SafetyStartCommandOperationTaskNoWait();
  }
  break;

  case SAFETY_MESSAGE_EXECUTE_USER_ALREADY_EXISTS:
  {
    PRINT("[safety]: user already exists.\r\n");

    SafetyBitStatus.MessageExecuteStep = SAFETY_MESSAGE_RESPONSE_EXCEPTION;
    SafetyBitStatus.CommandExecuteResult = SAFETY_COMMAND_USER_ALREADY_EXISTS;
    SafetyStartCommandOperationTaskNoWait();
  }
  break;

  default:
  {
    PRINT("[safety]: command execution failed.\r\n");

    SafetyBitStatus.CommandExecuteResult = SAFETY_COMMAND_ERROR;
    SafetyBitStatus.MessageExecuteStep = SAFETY_MESSAGE_RESPONSE_EXCEPTION;
    SafetyStartCommandOperationTaskNoWait();
  }
  break;
  }
}

static void SafetyReportingCommandExecutionResults(SafetyCommandTable_t Command, SafetyCommandExecuteResult_t Result)
{
  switch (Command)
  {
  case SAFETY_SELF_TEST:
    SafetyReportgSeltTestResult(Result);
    break;

  case SAFETY_FACTORY_SETTING:
    SafetyNotificationResetResults(Result);
    break;

  case SAFETY_GET_EIGENVALUE_FILE:
    SafetyNotificationGetEigenvalueFileResult(Result);
    break;

  case SAFETY_LOCAL_REGISTER_USER:
    SafetyReportLocalRegisterKeyResult(Result);
    break;

  case SAFETY_REGISTER_BY_EIGENVALUE:
    SafertReportOnlineRegisterKeyResult(Result);
    break;

  case SAFETY_IDENTIFY_USER_RIGHTS:
    SafetyReportUserAuthenticationResult(Result);
    break;

  case SAFETY_DELETE_SPECIFIC_USER:
    SafetyOperationAfterDeleteSpecificUserManual();
    break;

  default:
    break;
  }
}

static void SafetyDataReceivedCallback(void)
{
  PRINT("[safety]: rx length: %d, data: ", SafetyDataPacket.DataSize);
  for (uint16_t i = 0; i < SafetyDataPacket.DataSize; i++)
    PRINT("%02X", SafetyDataPacket.DataBuff[i]);
  PRINT(".\r\n");

  if (SafetyBitStatus.TransmitIdent == true)
  {
    uint16_t AttachedDataSize = 0;
    uint8_t ParsingResult = 0, AttachedData[SAFETY_MESSAGE_PACKET_LENGTH] = {0};

    if (SafetyVerifyMessageValidity(SafetyDataPacket.DataBuff, AttachedData, &AttachedDataSize, &ParsingResult) == true)
    {
      SafetyBitStatus.TransmitIdent = false;

      SafetyMessageExecuteResult_t MessageParsingResults = SafetyParsingMessagesBasedOnCommands(SafetyBitStatus.CurrentCommand, AttachedData, AttachedDataSize, ParsingResult);
      SafetyResponseMessageParsingResult(MessageParsingResults);
    }
  }

  SafetyDataPacket.DataSize = 0;
}

static void SafetyEventWakeupIrqCallback(void)
{
  PRINT("[safety]: event wakeup.\r\n");
}

static void SafetyCommandOperationCallback(void)
{
  switch (SafetyBitStatus.MessageExecuteStep)
  {
  case SAFETY_PREPARATION_FOR_SENDING:
  {
    PRINT("[safety]: task initialization, currently executing command: %02X.\r\n", SafetyBitStatus.CurrentCommand);

#if _SAFETY_MODULE_TYPE_ == _FACE_SAFETY_MODULE_
    SafetyBitStatus.TransmitIdent = true;
    SafetyBitStatus.MessageExecuteStep = SAFETY_LOAD_TIMEOUT;

#elif _SAFETY_MODULE_TYPE_ == _FINGER_SAFETY_MODULE_
    SafetyBitStatus.MessageExecuteStep = SAFETY_USER_ACTION_RESPONSE;
#endif

    SafetyDisableInterrupts();
    SafetyConfigurationNormalMode();
    SafetySetPowerContorlPinLevel(true);
    SafetyCommunicationsInitialization();
    SafetyDelayedStartCommandOperationTask(SAFETY_POWERUP_TASK_DELAY);
  }
  break;

  case SAFETY_USER_ACTION_RESPONSE:
  {
    if (SafetyBitStatus.NumberOfTimesSent < SAFETY_MAX_NUMBER_OF_SEND)
    {
      memset(&SafetyDataPacket, 0, sizeof(SafetyDataPacket_t));

      SafetyMessageCorrespondingCommand(SafetyBitStatus.CurrentCommand, SafetyDataPacket.DataBuff, &SafetyDataPacket.DataSize, &SafetyBitStatus.CommandTimeout);
      if ((SafetyDataPacket.DataSize) > 0 && (SafetyDataPacket.DataSize <= SAFETY_MESSAGE_PACKET_LENGTH))
      {
        {
          PRINT("[safety]: build message success, size: %d, data: ", SafetyDataPacket.DataSize);
          for (uint16_t i = 0; i < SafetyDataPacket.DataSize; i++)
            PRINT("%02X", SafetyDataPacket.DataBuff[i]);
          PRINT("\r\n");
        }

        {
          SafetyBitStatus.NumberOfTimesSent++;
          SafetyBitStatus.TransmitIdent = true;
          SafetyBitStatus.MessageExecuteStep = SAFETY_MESSAGE_DELIVERY_TIMEOUT;
          if (SafetyBitStatus.CommandTimeout < SAFETY_MESSAGE_SENGING_RATED_TIME)
          {
            SafetyBitStatus.CommandTimeout = SAFETY_MESSAGE_SENGING_RATED_TIME;
          }
        }

        {
          SafetyUartSendData(SafetyDataPacket.DataBuff, SafetyDataPacket.DataSize);
          SafetyDelayedStartCommandOperationTask(SafetyBitStatus.CommandTimeout);

          memset(&SafetyDataPacket, 0, sizeof(SafetyDataPacket_t));
        }
      }
      else
      {
        PRINT("[safety]: build message error.\r\n");

        SafetyBitStatus.MessageExecuteStep = SAFETY_COMMUNICATIONS_ANOMALY;
        SafetyStartCommandOperationTaskNoWait();
      }
    }
    else
    {
      PRINT("[safety]: maximum number of transmissions exceeded.\r\n");

      SafetyBitStatus.MessageExecuteStep = SAFETY_COMMUNICATIONS_ANOMALY;
      SafetyStartCommandOperationTaskNoWait();
    }
  }
  break;

  case SAFETY_MESSAGE_DELIVERY_TIMEOUT:
  {
    PRINT("[safety]: message delivery timeout.\r\n");

    SafetyBitStatus.TransmitIdent = false;
    SafetyBitStatus.MessageExecuteStep = SAFETY_USER_ACTION_RESPONSE;

    SafetyStartCommandOperationTaskNoWait();
  }
  break;

  default:
  {
    {
      SafetyConfigurationLowPower();
      SafetySetPowerContorlPinLevel(false);
      memset(&SafetyDataPacket, 0, sizeof(SafetyDataPacket_t));

      SafetyReportingCommandExecutionResults(SafetyBitStatus.CurrentCommand, SafetyBitStatus.CommandExecuteResult);
      PRINT("[safety]: %02X command executed. result: %02X.\r\n", SafetyBitStatus.CurrentCommand, SafetyBitStatus.CommandExecuteResult);
    }

    {
      bool CommandToExecute = false;

      if (SafetyBitStatus.DeleteIdent == true)
      {
        PRINT("[safety]: users exist to be deleted.\r\n");

        CommandToExecute = true;
        memset(&SafetyBitStatus, 0, sizeof(SafetyBitStatus_t));
        SafetyBitStatus.CurrentCommand = SAFETY_DELETE_SPECIFIC_USER;
        SafetyBitStatus.MessageExecuteStep = SAFETY_PREPARATION_FOR_SENDING;

        SafetyDelayedStartCommandOperationTask(SAFETY_POWERUP_TASK_DELAY);
      }
      else
      {
        if (SafetyBitStatus.MessageExecuteStep != SAFETY_MESSAGE_RESPONSE_COMPLETE)
        {
          if (SafetyBitStatus.CurrentCommand != SAFETY_FORCED_TO_GOTO_SLEEP)
          {
            PRINT("[safety]: forced to go to sleep.\r\n");

            CommandToExecute = true;
            memset(&SafetyBitStatus, 0, sizeof(SafetyBitStatus_t));
            SafetyBitStatus.CurrentCommand = SAFETY_FORCED_TO_GOTO_SLEEP;
            SafetyBitStatus.MessageExecuteStep = SAFETY_PREPARATION_FOR_SENDING;

            SafetyForcedToGotoSleepInitialization();
            SafetyDelayedStartCommandOperationTask(SAFETY_POWERUP_TASK_DELAY);
          }
        }
      }

      if (CommandToExecute == false)
      {
        PRINT("[safety]: all commands executed.\r\n");

        SafetyEnableInterrupts();
        memset(&SafetyBitStatus, 0, sizeof(SafetyBitStatus_t));
      }
    }
  }
  break;
  }
}
#endif

bool SafetyGetDeviceActiveEn(void)
{
#if _SAFETY_VERIFYFUNCTION_ENABLE_
  if (SafetyBitStatus.MessageBusyIdent == true)
    return true;
#endif

  return false;
}

uint8_t SafetyGetTheNumberOfUsers(void)
{
  uint8_t NumberOfRegistered = 0;

#if _SAFETY_VERIFYFUNCTION_ENABLE_
  NumberOfRegistered = SafetyGetTheNumberOfRegisteredUsers();
#endif

  return NumberOfRegistered;
}

void SafetyGetTheModuleSerialNumber(char *pSerialNumberOut)
{
#if _SAFETY_VERIFYFUNCTION_ENABLE_
  SafetyGetDeviceSerialNumber(pSerialNumberOut);
#endif
}

void SafetyGetTheModuleApplicationVersion(char *pVersionOut)
{
#if _SAFETY_VERIFYFUNCTION_ENABLE_
  SafetyGetApplicationVersion(pVersionOut);
#endif
}

void SafetyGetTheModuleAlgorithmVersion(char *pVersionOut)
{
#if _SAFETY_VERIFYFUNCTION_ENABLE_
  SafetyGetAlgorithmVersion(pVersionOut);
#endif
}

bool SafetyStartDeviceSelfTestTask(void)
{
#if _SAFETY_VERIFYFUNCTION_ENABLE_
  if (SafetyBitStatus.MessageBusyIdent != true)
  {
    memset(&SafetyBitStatus, 0, sizeof(SafetyBitStatus_t));

    SafetyBitStatus.MessageBusyIdent = true;
    SafetyBitStatus.CurrentCommand = SAFETY_SELF_TEST;
    SafetyBitStatus.MessageExecuteStep = SAFETY_PREPARATION_FOR_SENDING;

    SafetyStartCommandOperationTaskNoWait();

    return true;
  }
#endif

  return false;
}

bool SafetyStartDeviceFactorySettingTask(void)
{
#if _SAFETY_VERIFYFUNCTION_ENABLE_
  memset(&SafetyBitStatus, 0, sizeof(SafetyBitStatus_t));

  SafetyBitStatus.MessageBusyIdent = true;
  SafetyBitStatus.CurrentCommand = SAFETY_FACTORY_SETTING;
  SafetyBitStatus.MessageExecuteStep = SAFETY_PREPARATION_FOR_SENDING;

  SafetyStartCommandOperationTaskNoWait();

  return true;
#endif

  return false;
}

bool SafetyStartForcedToGotoSleepTask(void)
{
#if _SAFETY_VERIFYFUNCTION_ENABLE_
  memset(&SafetyBitStatus, 0, sizeof(SafetyBitStatus_t));

  SafetyBitStatus.MessageBusyIdent = true;
  SafetyBitStatus.CurrentCommand = SAFETY_FORCED_TO_GOTO_SLEEP;
  SafetyBitStatus.MessageExecuteStep = SAFETY_PREPARATION_FOR_SENDING;

  SafetySetPowerContorlPinLevel(false);
  SafetyForcedToGotoSleepInitialization();
  SafetyDelayedStartCommandOperationTask(SAFETY_POWERUP_TASK_DELAY);

  return true;

#else
  return false;
#endif
}

bool SafetyStartGetUserSpecificEigenvalueFilesTask(uint16_t UserId)
{
#if _SAFETY_VERIFYFUNCTION_ENABLE_
  if (SafetyBitStatus.MessageBusyIdent != true)
  {
    memset(&SafetyBitStatus, 0, sizeof(SafetyBitStatus_t));

    SafetyBitStatus.MessageBusyIdent = true;
    SafetyBitStatus.CurrentCommand = SAFETY_GET_EIGENVALUE_FILE;
    SafetyBitStatus.MessageExecuteStep = SAFETY_PREPARATION_FOR_SENDING;
    SafetyStartCommandOperationTaskNoWait();

    SafetyFlaggingTargetUsersToGetFeatureValueFiles(UserId);
    return true;
  }
#endif

  return false;
}

bool SafetyStartLocalRegisterUserTask(void)
{
#if _SAFETY_VERIFYFUNCTION_ENABLE_
  if (SafetyBitStatus.MessageBusyIdent != true)
  {
    memset(&SafetyBitStatus, 0, sizeof(SafetyBitStatus_t));

    SafetyBitStatus.MessageBusyIdent = true;
    SafetyBitStatus.CurrentCommand = SAFETY_LOCAL_REGISTER_USER;
    SafetyBitStatus.MessageExecuteStep = SAFETY_PREPARATION_FOR_SENDING;
    SafetyDelayedStartCommandOperationTask((SAFETY_DELAY_OF_LOCAL_REGISTER_USER * 2.5) * 1000);

    SafetyStartLocalRegisterTask(SAFETY_DELAY_OF_LOCAL_REGISTER_USER);
    return true;
  }

#endif

  return false;
}

bool SafetyStartUserAuthenticationTask(void)
{
#if _SAFETY_VERIFYFUNCTION_ENABLE_
  if (SafetyBitStatus.MessageBusyIdent != true)
  {
    if (SafetyGetTheNumberOfRegisteredUsers() > 0)
    {
      memset(&SafetyBitStatus, 0, sizeof(SafetyBitStatus_t));

      SafetyBitStatus.MessageBusyIdent = true;
      SafetyBitStatus.CurrentCommand = SAFETY_IDENTIFY_USER_RIGHTS;
      SafetyBitStatus.MessageExecuteStep = SAFETY_PREPARATION_FOR_SENDING;
      SafetyDelayedStartCommandOperationTask(SAFETY_DELAY_OF_IDENTIFY_USER_RIGHTS);

      SafetyStartAuthenticationTask();
      return true;
    }
  }
#endif

  return false;
}

bool SafetyStartDeletingSpecificUsersTask(uint16_t DeleteUserId)
{
#if _SAFETY_VERIFYFUNCTION_ENABLE_
  if (SafetyGetTheNumberOfRegisteredUsers() > 0)
  {
    if (SafetyBitStatus.MessageBusyIdent != true)
    {
      memset(&SafetyBitStatus, 0, sizeof(SafetyBitStatus_t));

      SafetyBitStatus.MessageBusyIdent = true;
      SafetyBitStatus.CurrentCommand = SAFETY_DELETE_SPECIFIC_USER;
      SafetyBitStatus.MessageExecuteStep = SAFETY_PREPARATION_FOR_SENDING;
      SafetyDelayedStartCommandOperationTask(SAFETY_DELAY_OF_DELETE_USER);

      SafetyPreparationBeforeDeletingUser();
    }

    SafetyBitStatus.DeleteIdent = true;
    SafetyRecordUsersToBeDeleted(DeleteUserId);

    return true;
  }
#endif

  return false;
}

bool SafetyStartRegisteringUsersByFeatureValueTask(void)
{
#if _SAFETY_VERIFYFUNCTION_ENABLE_
  if (SafetyBitStatus.MessageBusyIdent != true)
  {
    memset(&SafetyBitStatus, 0, sizeof(SafetyBitStatus_t));

    SafetyBitStatus.MessageBusyIdent = true;
    SafetyBitStatus.CurrentCommand = SAFETY_REGISTER_BY_EIGENVALUE;
    SafetyBitStatus.MessageExecuteStep = SAFETY_PREPARATION_FOR_SENDING;
    SafetyStartCommandOperationTaskNoWait();

    return true;
  }
#endif

  return false;
}

void SafetyConfiguration(void)
{
#if _SAFETY_VERIFYFUNCTION_ENABLE_
  SafetyExternFunctionTable_t ExternFunction = {0};

  ExternFunction.UartRxDoneCallBack = SafetyDataReceivedCallback;
  ExternFunction.EventWakeupCallback = SafetyEventWakeupIrqCallback;
  ExternFunction.CommandOperationCallback = SafetyCommandOperationCallback;
  SafetyBoardBoardInitialisation(&SafetyTaskApi, &SafetyDataPacket, &ExternFunction);

  memset(&SafetyBitStatus, 0, sizeof(SafetyBitStatus_t));
  memset(&SafetyDataPacket, 0, sizeof(SafetyDataPacket_t));
#endif
}
